#include "TextureClassification.h"

using namespace std;
using namespace pip;

/**
 * Performs a separable convolution. The first dimension is convolved with the first
 * kernel in kernels, and so on.
 *
 * @param in Input image
 * @param out Output image
 * @param kernels List of kernels
 * @param bi Border information
 */
void filterSeparable(const Image<float>& in, Image<float>& out, const vector<vector<float> >& kernels, const BorderInfo& bi)
{
  if (in.nrDims() != kernels.size()) {
    cerr << "Incorrect dimensions." << endl;
    return;
  }

  // Find out what the largest kernel half size is,
  // we need a border of this size
  int n(0);
  for (int i = 0; i < (int)kernels.size(); ++i) {
    if ((int)kernels[i].size() / 2 > n) {
      n = kernels[i].size() / 2;
    }
  }

  Image<float> temp1(in.bordered(n, bi));
  Image<float> temp2(in.dimension(), n, bi);
  temp2.fill(0);
  out.resize(in.dimension());
  out.fill(0);

  // First along x-direction,
  // store result in temp2
  vector<float> kernel = kernels[0];
  n = kernel.size() / 2;
  for (int y = 0; y < in.dim(1); ++y) {
    for (int x = 0; x < in.dim(0); ++x) {
      for (int i = -n; i <= n; ++i) {
        temp2(x, y) += temp1(x - i, y) * kernel[i + n];
      }
    }
  }

  // Now along y-direction,
  // store result in out
  kernel = kernels[1];
  n = kernel.size() / 2;
  for (int y = 0; y < in.dim(1); ++y) {
    for (int x = 0; x < in.dim(0); ++x) {
      for (int i = -n; i <= n; ++i) {
        out(x, y) += temp2(x, y - i) * kernel[i + n];
      }
    }
  }
}


typedef pair<int, int> Pos;
typedef pair<float, Pos> ValuePos;

void preprocess(const Image<float>& in, Image<float>& out)
{
  vector<ValuePos> v;
  const int xDim(in.dim(0)), yDim(in.dim(1));
  for (int y = 0; y < yDim; ++y) {
    for (int x = 0; x < xDim; ++x) {
      v.push_back(ValuePos(in(x, y), Pos(x, y)));
    }
  }
  sort(v.begin(), v.end());

  out.resize(in.dimension());
  const unsigned int vSize(v.size());
  for (unsigned int i = 0; i < vSize; ++i) {
    out(v[i].second.first, v[i].second.second) = (float)i;
  }
}

void histogram(const Image<float>& in, vector<float>& h, const int& nrbins)
{
	h.clear(); // clear vector to avoid side-effects
	//get one entry for every bin
	for(int fill = 0; fill < nrbins; ++fill){
		h.push_back(0);
	}

	//init
	float min(0),max(0),binsize(0);
	getMinMaxImage(in,min,max); //to determine bin-size
	binsize = abs(max-min)/nrbins;
	
	for(int x=0;x<in.dim(0);++x){
		for(int y=0;y<in.dim(1);++y){
			if(in(x,y)==max){
				h[nrbins-1]++;
			}else{
				h[int((in(x,y)-min)/binsize)]++;  // increment histogram 
			}
		}
	}
	for(int norm = 0; norm < nrbins; ++norm){
		h[norm]/=in.dim(0)*in.dim(1);
	}
}


void Law3(const Image<float>& in, Image<float>& out, const string& filter)
{
	vector<vector<float> > kernels;  //prepare sep. kernels
	float *initx,*inity;             // to point to local variables
	char me(filter[0]),you(filter[1]); // remember the two CHARs

	if(me=='L'){
		float ar[3]={1,2,1};initx=ar; // we use an array to init the vector
	}else if(me=='E'){
		float ar[3]={-1,0,1};initx=ar;
	}else if(me=='S'){
		float ar[3]={-1,2,-1};initx=ar;
	}

	if(you=='L'){
		float ar[3]={1,2,1};inity=ar;
	}else if(you=='E'){
		float ar[3]={-1,0,1};inity=ar;
	}else if(you=='S'){
		float ar[3]={-1,2,-1};inity=ar;
	}

	vector<float> tmpx(initx,initx+3); // init vector 
	vector<float> tmpy(inity,inity+3);
	kernels.push_back(tmpx); // use it as kernel
	kernels.push_back(tmpy);

	filterSeparable(in,out,kernels,border_mirror); // convolve!
}